package cn.miju.admin.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.miju.admin.framework.constant.AdminConstant;
import cn.miju.admin.biz.service.PayOrderService;
import cn.miju.admin.biz.vo.PayOrderPageInVO;
import cn.miju.admin.biz.vo.PayOrderPageOutVO;
import cn.miju.database.entity.Merchant;
import cn.miju.database.entity.PayOrder;
import cn.miju.database.entity.RefundOrder;
import cn.miju.database.service.PayOrderDataService;
import cn.miju.database.service.RefundOrderDataService;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <pre>
 * 支付订单管理
 * </pre>
 *
 * @author zhuming
 * @version 1.0.0
 * @since 2023-04-07 11:37
 */
@Service
@RequiredArgsConstructor
public class PayOrderServiceImpl implements PayOrderService {
    private final PayOrderDataService payOrderDataService;
    private final RefundOrderDataService refundOrderDataService;
    private final StringRedisTemplate redisTemplate;
    /**
     * 支付订单分页查询
     * @param inVO {@link PayOrderPageInVO}
     * @return {@link Page<PayOrderPageOutVO>}
     */
    @Override
    public Page<PayOrderPageOutVO> getPage(PayOrderPageInVO inVO) {
        LambdaQueryWrapper<PayOrder> queryWrapper = Wrappers.lambdaQuery();
        if (StringUtils.isNotBlank(inVO.getOrderNo())) {
            queryWrapper.like(PayOrder::getPlatTradeNo, inVO.getOrderNo());
        }
        if (Objects.nonNull(inVO.getPayWay())) {
            queryWrapper.eq(PayOrder::getPayWay, inVO.getPayWay());
        }
        if (Objects.nonNull(inVO.getStartTime()) && Objects.nonNull(inVO.getEndTime())) {
            LocalDateTime startTime = inVO.getStartTime().withHour(0).withMinute(0).withSecond(0);
            LocalDateTime endTime = inVO.getEndTime().withHour(23).withMinute(59).withSecond(59);
            queryWrapper.ge(PayOrder::getCreatedTime, startTime);
            queryWrapper.le(PayOrder::getCreatedTime, endTime);
        }
        Page<PayOrder> payOrderPage = payOrderDataService.page(new Page<>(inVO.getPage(), inVO.getPageSize()), queryWrapper);
        Page<PayOrderPageOutVO> page = new Page<>();
        BeanUtil.copyProperties(payOrderPage, page);
        if (CollUtil.isNotEmpty(payOrderPage.getRecords())) {
            List<RefundOrder> refundOrderList = refundOrderDataService.list(Wrappers.<RefundOrder>lambdaQuery().
                    in(RefundOrder::getPayOrderId, payOrderPage.getRecords().stream().map(PayOrder::getId).collect(Collectors.toList())));
            Map<Long, List<RefundOrder>> refundOrderMap = Maps.newHashMap();
            if (CollUtil.isNotEmpty(refundOrderList)) {
                refundOrderMap.putAll(refundOrderList.stream().collect(Collectors.groupingBy(RefundOrder::getPayOrderId, Collectors.mapping(refundOrder -> refundOrder, Collectors.toList()))));
            }
            page.setRecords(payOrderPage.getRecords().stream().map(payOrder -> {
                PayOrderPageOutVO outVO = new PayOrderPageOutVO();
                outVO.setId(payOrder.getId());
                outVO.setOrderNo(payOrder.getPlatTradeNo());
                outVO.setOutOrderNo(payOrder.getOutTradeNo());
                String merchantInfoKey = AdminConstant.Redis.MERCHANT_INFO + payOrder.getMerchantId();
                if (Boolean.TRUE.equals(redisTemplate.hasKey(merchantInfoKey))) {
                    Merchant merchant = JSONObject.parseObject(redisTemplate.opsForValue().get(merchantInfoKey), Merchant.class);
                    outVO.setMerchantName(merchant.getMerchantName());
                }
                outVO.setPayScen(payOrder.getPayScen());
                outVO.setPayWay(payOrder.getPayWay());
                outVO.setAmount(payOrder.getPayAmount());
                outVO.setStatus(payOrder.getStatus());
                outVO.setCreatedOrderTime(payOrder.getCreatedOrderTime());
                outVO.setPayOrderTime(Objects.isNull(payOrder.getPayOrderTime()) ? null : payOrder.getPayOrderTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                outVO.setRefundRecords(Collections.emptyList());
                if (refundOrderMap.containsKey(payOrder.getId())) {
                    outVO.setRefundRecords(refundOrderMap.get(payOrder.getId()).stream().map(refundOrder -> {
                        PayOrderPageOutVO.RefundRecord refundRecord = new PayOrderPageOutVO.RefundRecord();
                        refundRecord.setRefundNo(refundOrder.getPlatRefundNo());
                        refundRecord.setOutRefundNo(refundOrder.getOutRefundNo());
                        refundRecord.setAmount(refundOrder.getRefundAmount());
                        refundRecord.setRefundStatus(String.valueOf(refundOrder.getStatus()));
                        refundRecord.setRefundCreatedTime(refundOrder.getCreatedTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                        refundRecord.setRefundFinishTime(Objects.isNull(refundOrder.getRefundTime()) ? null : refundOrder.getRefundTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                        return refundRecord;
                    }).collect(Collectors.toList()));
                }
                return outVO;
            }).collect(Collectors.toList()));
        }
        return page;
    }
}
